﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using DateBaseConnectionPool;
using MySql.Data.MySqlClient;
using System.Data.Common;
using System.Threading;
using System.Text.RegularExpressions;
using System.Windows.Forms;
using System.IO;

namespace TestMySqlConnetPoll
{
    /// <summary>
    /// 全局变量定义
    /// </summary>
    
    #region   基础结构定义，时间结构体，模拟量值结构体
    public struct objDate
    {
        public int year;
        public byte month;
        public byte day;
        public objDate(int Iyear,int Imonth,int Iday)
        {
            year = Iyear;
            month = (byte)Imonth;
            day = (byte)Iday;
        }

        public override string ToString()
        {
            return MySql.objDateToDateTime(this).ToString("D");;
        }
    }
    
    public class objAnalogDev      //设备->时间+值列表
    {
        public Int16 dev_no = -1;
        public List<objTimeValue> dValue = new List<objTimeValue>();
    }

    #endregion

    public static class MySql
    {
        static public  ConnectionPool c = null;
        static public int key = 0;
        static public string CurrentUserName = "";

        #region 回放变量
       static public Dictionary<byte, List<ObjAlaram>> AlarmReplayValueList = new Dictionary<byte, List<ObjAlaram>>();
       static public Dictionary<AnalogCodeType, List<ReplayClass>> AnalogReplayValueList = new Dictionary<AnalogCodeType, List<ReplayClass>>();
       static public Dictionary<AnalogCodeType, List<HighReplayClass>> HighAnalogReplayValueList = new Dictionary<AnalogCodeType, List<HighReplayClass>>();
       static public List<ObjKGL> KGL_ReplayValueList = new List<ObjKGL>();
      
        #endregion

        #region    构造函数
        public static void InitMySql(string DataBaseName, string ConnectName)
        {
            if (DataBaseName == "") DataBaseName = "csm2014";
            if (ConnectName == "") ConnectName = "192.168.10.222";
            c = new ConnectionPool(DataBaseName, ConnectName);
            //c = new ConnectionPool(DataBaseName, ConnectName,"yes","root","root","utf8");
            c.MinConnection = 15;
            c.MaxConnection = 50;
            c.MaxRepeatDegree = 40;
            c.SeepConnection = 20;
            c.KeepRealConnection = 15;
            c.StartServices();
        }

        static void InitMySql()
        {
            c = new ConnectionPool("csm2010", "localhost");
            c.MinConnection = 5;
            c.MaxConnection = 20;
            c.MaxRepeatDegree = 10;
            c.SeepConnection = 5;
            c.KeepRealConnection = 5;
            c.StartServices();
        }
                
        #endregion

        public static void InsertUserScanT(string ScanType, string ScanNo, DateTime time_s, DateTime time_e,string strTE)
        {
            UserScanTable usstb = new UserScanTable();
            objTableScanAnnal usobj = new objTableScanAnnal(MySql.DateTimeToTime_t(time_s), MySql.DateTimeToTime_t(time_e));
            usobj.strTableE = strTE;
            usstb.InsertTableScanData(ScanType, ScanNo, usobj);
        }

        static public String replaceBlank(String str)
        {
            String result = str;
            if (str != null)
            {
                result = Regex.Replace(result, @"\s*|\t|\r|\n", "", RegexOptions.IgnoreCase);
                result = Regex.Replace(result, "（", "(", RegexOptions.IgnoreCase);
                result = Regex.Replace(result, "）", ")", RegexOptions.IgnoreCase);
            }
            return result;
        }

        #region    时间转换函数

        public static objDate DateTimeToobjDate(DateTime obj)
        {
            objDate t = new objDate();
            t.day = (byte)obj.Day;
            t.month = (byte)obj.Month;
            t.year = obj.Year;
            return t;
        }

        public static DateTime objDateToDateTime(objDate obj)
        {
            return new DateTime(obj.year, obj.month, obj.day);
        }

        public static objDate Time_tToObjDate(int u_time)
        {
            DateTime t = Time_tToDateTime(u_time);
            objDate obj = new objDate();
            obj.year = t.Year;
            obj.month = (byte)t.Month;
            obj.day = (byte)t.Day;
            return obj;
        }

        public static int ObjDateToTime_t(objDate date)
        {
            DateTime t = new DateTime(date.year, date.month, date.day);
            long l = DateTimeToTime_t(t);
            return (int)l;            
        }
        /// <summary>
        /// 将unix时间转换成系统时间
        /// </summary>
        /// <param name="u_time"></param>
        /// <returns></returns>
        public static DateTime Time_tToDateTime(int u_time)
        {
            DateTime t = System.DateTime.MinValue;
            
            DateTime dtStart = TimeZone.CurrentTimeZone.ToLocalTime(new DateTime(1970, 1, 1));
            
            t = dtStart.AddSeconds(u_time);
            return t;
        }
        /// <summary>
        /// 系统时间转换成unix时间
        /// </summary>
        /// <param name="dateTime"></param>
        /// <returns></returns>
        public static int DateTimeToTime_t(DateTime dateTime)
        {
            DateTime dt1 = TimeZone.CurrentTimeZone.ToLocalTime(new DateTime(1970, 1, 1));
            TimeSpan ts = dateTime - dt1;
            int Result = (int)ts.TotalSeconds;
            return Result;
        }
        #endregion

        public static HistroyAlarmObj ConvertAlarmObjToDisplay(ObjAlaram obj)
        {
            HistroyAlarmObj re = new HistroyAlarmObj();
            re.alarmObj = c_NetData.Clone(obj) as ObjAlaram;
            re.u_time = Time_tToDateTime(obj.u_time).ToString().Replace("\0", "").Trim();
            re.AlarmLevel_int = obj.AlarmLevel;
            re.AlarmLevel = obj.AlarmLevel.ToString().Replace("\0", "").Trim();
            if (re.AlarmLevel == "1")
                re.AlarmLevel = "一级报警";
            else if (re.AlarmLevel == "2")
                re.AlarmLevel = "二级报警";
            else if (re.AlarmLevel == "3")
                re.AlarmLevel = "三级报警";
            else if (re.AlarmLevel == "4")
                re.AlarmLevel = "预警";
            re.AlarmType = c_Device.GetAlarmTypeName(obj.AlarmType).Replace("\0", "").Trim();
            re.ex_AlarmType = obj.ex_AlarmType.ToString().Replace("\0", "").Trim();
            if (obj.statue == 0) re.statue = "";
            if (obj.e_time != 0) re.statue = "已恢复";
            if (obj.ConfirmTime != 0) re.statue += "已处理";
            if (obj.tcFlag == 1) re.tcFlag = "√";
            else re.tcFlag = "";
            
            if (obj.e_time != 0)
            {
                re.e_time = Time_tToDateTime(obj.e_time).ToString().Replace("\0", "").Trim();
            }
            if (obj.d_time != 0)
            {
                re.d_time = Time_tToDateTime(obj.d_time).ToString().Replace("\0", "").Trim();
            }
            if(obj.dev_type == 0xf1)    //信号非正常关闭报警
            {
                re.dev_type = "信号机";
                re.AnalogName = obj.devName;
                re.devName = obj.devName;
                re.DevTypeName = "信号机";
            }
            else if(obj.dev_type == 0xf2) // 列车信号主灯丝断报警
            {
                re.dev_type = "信号机";
                re.AnalogName = obj.devName;
                re.devName = obj.devName;
                re.DevTypeName = "信号机";
            }
            else if(obj.dev_type == 0xf3) //ZPW2000系统报警
            {
                re.dev_type = "ZPW2000接口";
                re.AnalogName = obj.devName;
                re.devName = obj.devName;
                re.DevTypeName = "ZPW2000接口";
            }
            else if(obj.dev_type == 0xf4) //列控系统报警
            {
                re.dev_type = "列控系统";
                re.AnalogName = obj.devName;
                re.devName = obj.devName;
                re.DevTypeName = "列控系统";
            }
            else if(obj.dev_type == 0x31) //转辙机缺口报警
            {
                re.dev_type = "转辙机缺口";
                re.AnalogName = obj.devName;
                re.devName = obj.devName;
                re.DevTypeName = "转辙机缺口";
            }
            else if (obj.dev_type == 0x10) //道岔报警
            {
                re.dev_type = "转辙机";
                re.AnalogName = obj.devName;
                re.devName = obj.devName;
                re.DevTypeName = "转辙机";
            }
            else if (obj.dev_type == 0xf5)
            {
                re.dev_type = "开关量";
                re.AnalogName = obj.devName;
                re.devName = obj.devName;
                re.DevTypeName = "开关量";
            }
            else if(obj.dev_type == 0xf6)
            {
                re.dev_type = "道岔";
                re.AnalogName = obj.devName;
                re.devName = obj.devName;
                re.DevTypeName = "道岔";
            }
            else if(obj.dev_type == 0xf7)
            {
                re.dev_type = "外电网";
                re.AnalogName = obj.devName;
                re.devName = obj.devName;
                re.DevTypeName = "外电网故障曲线";
            }
            else
            {
                try
                {
                    re.dev_type = c_Device.GetAnalogTypeName((AnalogCodeType)obj.dev_type);
                    re.AnalogName = c_Device.GetAnalogName(obj.dev_type, obj.dev_no);
                    CSM_DevType tmptype = c_Device.GetCSM_DevType((AnalogCodeType)obj.dev_type);
                    re.DevTypeName = c_Device.GetDevTypeName(tmptype);
                    re.devName = c_Device.GetCsm_DevName(tmptype, obj.dev_no);
                }
                catch (Exception e) { }
            }
            re.AlarmText = obj.AlarmText;
            if (obj.ConfirmName != null)
            {
                re.ConfirmName = obj.ConfirmName.Replace("\0", "").Trim();
            }
            if (obj.ConfirmText != null)
            {
                re.ConfirmText = obj.ConfirmText.Replace("\0", "").Trim();
            }
            if (obj.ConfirmTime != 0)
            {
                re.ConfirmTime = Time_tToDateTime(obj.ConfirmTime).ToString();
            }
            return re;
        }

        /// <summary>
        /// 报警结构转成字节数组
        /// </summary>
        /// <param name="obj"></param>
        /// <returns></returns>
        /// flag = 0 为实时包结构，flag =1 为历史包结构
        /// gztz =1 故障通知包结构
        static public List<byte> objAlarmToByteBuf(ObjAlaram obj, int flag ,int gztz)
        {
            ///报警传输协议
            ///gztz = 0 时：
            ///报警开始时间（4）
            ///报警结束时间（4）
            ///报警设备号（2）
            ///报警状态（2）
            ///flag == 0 时
            ///{
            ///   报警明文长度+报警设备名长度（1）
            ///   报警设备名长度（1）
            ///   报警设备名（n）
            ///   报警明文（n）
            ///}
            ///flag == 1 时
            ///{
            ///   报警设备名长度（1）
            ///   报警设备名（n）
            ///   报警明文长度（1）
            ///   报警明文（n）
            ///}
            ///后续字节总长度（2）
            ///报警级别 （1）
            ///报警类型 （1）
            ///扩展报警类型（1）
            ///设备类型（1）
            ///天窗标志（1）
            ///报警延迟时间（4）
            ///报警确认人名字字节数n（1）
            ///报警确认人名字 （n）
            ///报警确认时间（4）
            ///报警确认明文长度c (1)
            ///报警确认明文（c）
            ///gztz = 1 时
            ///通知时间 （4）
            ///受理时间（4）
            ///恢复时间（4）
            ///预留时间（4）
            ///故障原因长度（1）
            ///故障原因（n）
            List<byte> li = new List<byte>();
            if (gztz == 0)
            {
                li.Add((byte)obj.u_time);               //报警开始时间（4）
                li.Add((byte)(obj.u_time >> 8));
                li.Add((byte)(obj.u_time >> 16));
                li.Add((byte)(obj.u_time >> 24));
                li.Add((byte)obj.e_time);               //报警结束时间（4）
                li.Add((byte)(obj.e_time >> 8));
                li.Add((byte)(obj.e_time >> 16));
                li.Add((byte)(obj.e_time >> 24));
                li.Add((byte)obj.dev_no);               //报警设备号（2）
                li.Add((byte)(obj.dev_no >> 8));
                li.Add((byte)obj.statue);               //报警状态（2）
                li.Add(0);                              //状态高位

                byte[] atext = System.Text.Encoding.Default.GetBytes(obj.AlarmText); //报警明文
                byte[] devtext = System.Text.Encoding.Default.GetBytes(obj.devName);   //设备名
                int tlen = devtext.Length + atext.Length;  //报警内明文长度
                int devLen = devtext.Length;
                if (flag == 0)
                {
                    li.Add((byte)tlen);     //报警明文长度+报警设备名长度（1）
                    li.Add((byte)devLen);       //报警设备名长度（1）
                    li.AddRange(devtext);       //报警设备名（n）
                    li.AddRange(atext);         //报警明文（n）
                }
                else
                {
                    li.Add((byte)devLen);
                    li.AddRange(devtext);
                    li.Add((byte)atext.Length);
                    li.AddRange(atext);
                }

                byte[] nametext = System.Text.Encoding.Default.GetBytes(obj.ConfirmName);
                byte[] qrtext = System.Text.Encoding.Default.GetBytes(obj.ConfirmText);
                int nameLen = nametext.Length;
                int qrLen = qrtext.Length;

                int ylLen = 5 + 4 + 1 + nameLen + 4 + 1 + qrLen;

                li.Add((byte)ylLen);            //预留长度 （2）
                li.Add((byte)(ylLen >> 8));
                li.Add(obj.AlarmLevel);         //报警级别 （1）
                li.Add(obj.AlarmType);          //报警类型 （1）
                li.Add(obj.ex_AlarmType);       //扩展报警类型（1）
                li.Add(obj.dev_type);           //设备类型（1）
                li.Add(obj.tcFlag);             //天窗标志（1）
                li.Add((byte)obj.d_time);       //报警延迟时间（4）
                li.Add((byte)(obj.d_time >> 8));
                li.Add((byte)(obj.d_time >> 16));
                li.Add((byte)(obj.d_time >> 24));
                li.Add((byte)nameLen);          //报警确认人名字字节数n（1）
                li.AddRange(nametext);          //报警确认人名字 （n）
                li.Add((byte)obj.ConfirmTime);  //报警确认时间（4）
                li.Add((byte)(obj.ConfirmTime >> 8));
                li.Add((byte)(obj.ConfirmTime >> 16));
                li.Add((byte)(obj.ConfirmTime >> 24));
                li.Add((byte)qrLen);            //报警确认明文长度c (1)
                li.AddRange(qrtext);            //报警确认明文（c）
            }
            else
            {
                li.Add((byte)obj.u_time);
                li.Add((byte)(obj.u_time >> 8));
                li.Add((byte)(obj.u_time >> 16));
                li.Add((byte)(obj.u_time >> 24));
                li.Add((byte)obj.ConfirmTime);
                li.Add((byte)(obj.ConfirmTime >> 8));
                li.Add((byte)(obj.ConfirmTime >> 16));
                li.Add((byte)(obj.ConfirmTime >> 24));
                li.Add((byte)obj.e_time);
                li.Add((byte)(obj.e_time >> 8));
                li.Add((byte)(obj.e_time >> 16));
                li.Add((byte)(obj.e_time >> 24));
                li.Add((byte)obj.d_time);       //预留时间
                li.Add((byte)(obj.d_time >> 8));
                li.Add((byte)(obj.d_time >> 16));
                li.Add((byte)(obj.d_time >> 24));

                byte[] abuf = System.Text.Encoding.Default.GetBytes(obj.AlarmText);
                int alen = abuf.Length;

                li.Add((byte)alen);
                li.AddRange(abuf);
            }
            return li;
        }

        /// <summary>
        /// 字节数组转换成报警结构.
        /// </summary>
        /// <param name="sBuf"></param>
        /// <returns></returns>
        /// flag = 0 为实时包结构，=1 历史包结构
        /// gztz = 1 故障通知包结构
        static public List<ObjAlaram> byteBufToObjAlarmList(byte[] sBuf ,int offset,int flag ,int gztz)
        {
            List<ObjAlaram> li = new List<ObjAlaram>();
            int m = offset;
            int AlarmNum = sBuf[m] + (sBuf[m+1] << 8);
            m += 2;
            for (int i = 0; i < AlarmNum; i++)
            {
                ObjAlaram obj = new ObjAlaram();
                if (gztz == 0)
                {
                    obj.u_time = sBuf[m] + (sBuf[m + 1] << 8) + (sBuf[m + 2] << 16) + (sBuf[m + 3] << 24); //报警时间
                    m += 4;
                    obj.e_time = sBuf[m] + (sBuf[m + 1] << 8) + (sBuf[m + 2] << 16) + (sBuf[m + 3] << 24); //恢复时间
                    m += 4;
                    obj.dev_no = (short)(sBuf[m] + (sBuf[m + 1] << 8));    //设备序号
                    m += 2;
                    obj.statue = sBuf[m++]; //状态两字节
                    m++;
                    if (flag == 0)
                    {
                        int tlen = sBuf[m++];   //报警明文长度
                        int devLen = sBuf[m++]; //设备名称
                        obj.devName = System.Text.Encoding.Default.GetString(sBuf, m, devLen);
                        m += devLen;
                        obj.AlarmText = System.Text.Encoding.Default.GetString(sBuf, m, (tlen - devLen));
                        m += (tlen - devLen);
                    }
                    else
                    {
                        int devLen = sBuf[m++]; //设备名称
                        obj.devName = System.Text.Encoding.Default.GetString(sBuf, m, devLen);
                        m += devLen;
                        int tlen = sBuf[m++];
                        obj.AlarmText = System.Text.Encoding.Default.GetString(sBuf, m, tlen);
                        m += tlen;
                    }
                    int ylen = (sBuf[m] + (sBuf[m + 1] << 8));    //预留长度.
                    m += 2;
                    obj.AlarmLevel = sBuf[m++];
                    obj.AlarmType = sBuf[m++];
                    obj.ex_AlarmType = sBuf[m++];
                    obj.dev_type = sBuf[m++];
                    obj.tcFlag = sBuf[m++];
                    obj.d_time = sBuf[m] + (sBuf[m + 1] << 8) + (sBuf[m + 2] << 16) + (sBuf[m + 3] << 24); //延迟时间
                    m += 4;
                    int nameLen = sBuf[m++]; //报警确认人长度 
                    obj.ConfirmName = System.Text.Encoding.Default.GetString(sBuf, m, nameLen);
                    m += nameLen;
                    obj.ConfirmTime = sBuf[m] + (sBuf[m + 1] << 8) + (sBuf[m + 2] << 16) + (sBuf[m + 3] << 24);
                    m += 4;
                    int cLen = sBuf[m++];     //确认文字长度

                    obj.ConfirmText = System.Text.Encoding.Default.GetString(sBuf, m, cLen);
                    m += cLen;
                    li.Add(obj);
                }
                else
                {
                    obj.u_time = sBuf[m] + (sBuf[m + 1] << 8) + (sBuf[m + 2] << 16) + (sBuf[m + 3] << 24); //报警时间
                    m += 4;
                    obj.ConfirmTime = sBuf[m] + (sBuf[m + 1] << 8) + (sBuf[m + 2] << 16) + (sBuf[m + 3] << 24); //受理时间
                    m += 4;
                    obj.e_time = sBuf[m] + (sBuf[m + 1] << 8) + (sBuf[m + 2] << 16) + (sBuf[m + 3] << 24); //预留时间
                    m += 4;
                    obj.d_time = sBuf[m] + (sBuf[m + 1] << 8) + (sBuf[m + 2] << 16) + (sBuf[m + 3] << 24); //恢复时间
                    m += 4;
                    int tlen = sBuf[m++];
                    obj.AlarmText = System.Text.Encoding.Default.GetString(sBuf, m, tlen);
                    m += tlen;
                    li.Add(obj);
                }
            }
            return li;
        }

        struct rstruct
        {
           public DateTime stime;
           public int len;
        }

        static public void ReadReplayData(DateTime stime, int len)
        {
            rstruct obj = new rstruct();
            obj.stime = stime;
            obj.len = len;            
            ThreadPool.QueueUserWorkItem(new WaitCallback(GetReplay_Data), obj);
        }
        /// <summary>
        /// 获取回放数据线程.
        /// </summary>
        /// <param name="oo"></param>
        public static event EventHandler HasRepaly;
        static private void GetReplay_Data(object oo)
        {
            rstruct obj = (rstruct)oo;
            int stime =DateTimeToTime_t(obj.stime);
            int etime =DateTimeToTime_t(obj.stime.AddMinutes(obj.len)) ;

            string splitStr = "铁大电信回放";
            byte[] hh = System.Text.Encoding.Default.GetBytes(splitStr);
            AnalogTable at = new AnalogTable();
            at.ReadReplayValue(stime, etime);
            AnalogHigFreTable hat = new AnalogHigFreTable();
            hat.ReadReplayValue(stime, etime);
            KGL_Table kt = new KGL_Table();
            kt.Read_KGL_ValueList(stime, etime);
            AlarmTable art = new AlarmTable();
            List<string> sli = new List<string>();
            List<int>ili = new List<int>();
            art.Read_ValueList(Time_tToDateTime(stime), Time_tToDateTime(etime),sli,ili,"","");
            DateTime d = DateTime.Now;
            while(true)
            {
                if (at.ErrorFlag != 0) break;
                if (kt.ErrorFlag != 0) break;
                if (hat.ErrorFlag != 0) break;
                if (art.ErrorFlag != 0) break;
                if (DateTime.Now.Subtract(d).TotalSeconds > 150) break;
                Thread.Sleep(50);
                if (at.Ready_ReplayValueList && kt.Ready_KGL_ValueList && hat.Ready_ReplayValueList && art.Ready_AlarmValueList) break;
            }
            if(at.Ready_ReplayValueList &&kt.Ready_KGL_ValueList&&hat.Ready_ReplayValueList&&art.Ready_AlarmValueList)
            {
                if (at.ReplayValueList.Count == 0 || kt.KGL_ValueList.Count == 0)
                {
                    MessageBox.Show("没有获取到回放数据");
                    return;
                }                
                List<byte> li = new List<byte>();
                li.AddRange(hh);
                //模拟量数据入队列
                List<AnalogCodeType> keys = at.ReplayValueList.Keys.ToList();
                li.Add((byte)keys.Count);   //模拟量类型数目                
                for(int i = 0;i<keys.Count;i++)
                {                    
                    AnalogCodeType a = keys[i];
                    int atype = (int)a;
                    li.Add((byte)atype);        //模拟量类型
                    li.Add((byte)(atype >> 8));
                    List<ReplayClass> rc = at.ReplayValueList[a];                    
                    li.Add((byte)rc.Count);         //该种模拟量类型下的设备个数
                    li.Add((byte)(rc.Count >> 8));
                    for(int j = 0;j<rc.Count;j++)
                    {
                        ReplayClass orc = rc[j];
                        li.Add((byte)orc.AnalogNo);
                        li.Add((byte)(orc.AnalogNo >> 8));
                        li.Add((byte)orc.ValueList.Count);
                        li.Add((byte)(orc.ValueList.Count >> 8));
                        for(int k = 0;k<orc.ValueList.Count;k++)
                        {
                            objTimeValue otv = orc.ValueList[k];
                            li.Add((byte)otv.u_time);
                            li.Add((byte)(otv.u_time >> 8));
                            li.Add((byte)(otv.u_time >> 16));
                            li.Add((byte)(otv.u_time >> 24));
                            li.Add((byte)otv.Dvalue);
                            li.Add((byte)(otv.Dvalue >> 8));
                        }
                    }
                }
                li.AddRange(hh);
                //高频模拟量数据入队列
                List<AnalogCodeType> gkeys = hat.ReplayValueList.Keys.ToList();
                li.Add((byte)gkeys.Count);   //模拟量类型数目                
                for (int i = 0; i < gkeys.Count; i++)
                {
                    AnalogCodeType a = gkeys[i];
                    int atype = (int)a;
                    li.Add((byte)atype);        //模拟量类型
                    li.Add((byte)(atype >> 8));
                    List<HighReplayClass> rc = hat.ReplayValueList[a];
                    li.Add((byte)rc.Count);         //该种模拟量类型下的设备个数
                    li.Add((byte)(rc.Count >> 8));
                    for (int j = 0; j < rc.Count; j++)
                    {
                        HighReplayClass orc = rc[j];
                        li.Add((byte)orc.AnalogNo);
                        li.Add((byte)(orc.AnalogNo >> 8));
                        li.Add((byte)orc.ValueList.Count);
                        li.Add((byte)(orc.ValueList.Count >> 8));
                        for (int k = 0; k < orc.ValueList.Count; k++)
                        {
                            HigFreAnalogValue otv = orc.ValueList[k];
                            li.Add((byte)otv.utime);
                            li.Add((byte)(otv.utime >> 8));
                            li.Add((byte)(otv.utime >> 16));
                            li.Add((byte)(otv.utime >> 24));
                            li.Add((byte)otv.SecondValueList.Count);
                            li.Add((byte)(otv.SecondValueList.Count>>8));
                            for(int x = 0;x<otv.SecondValueList.Count;x++)
                            {
                                objHigFre ov = otv.SecondValueList[x];
                                li.Add((byte)ov.wValue);
                                li.Add((byte)(ov.wValue >> 8));
                            }
                        }
                    }
                }
                li.AddRange(hh);
                //开关量数据入队列
                li.Add((byte)kt.KGL_ValueList.Count);
                li.Add((byte)(kt.KGL_ValueList.Count >> 8));
                for(int i = 0;i<kt.KGL_ValueList.Count;i++)
                {
                    ObjKGL ok = kt.KGL_ValueList[i];
                    li.Add((byte)ok.u_time);
                    li.Add((byte)(ok.u_time >> 8));
                    li.Add((byte)(ok.u_time >> 16));
                    li.Add((byte)(ok.u_time >> 24));
                    li.Add((byte)ok.type);
                    li.Add((byte)ok.len);
                    li.Add((byte)(ok.len >> 8));
                    for(int j = 0;j<ok.len ;j++)
                    {
                        li.Add(ok.v[j]);
                    }
                }
                li.AddRange(hh);
                //报警数据入队列
                li.Add((byte)art.ValueList.Count);
                li.Add((byte)(art.ValueList.Count >> 8));
                List<byte>akey = art.ValueList.Keys.ToList();
                for(int i = 0;i<akey.Count;i++)
                {
                    byte k = akey[i];
                    li.Add(k);
                    li.Add((byte)art.ValueList[k].Count);
                    li.Add((byte)(art.ValueList[k].Count >> 8));
                    for(int j = 0;j<art.ValueList[k].Count;j++)
                    {
                        ObjAlaram o = art.ValueList[k][j];
                        List<byte> t = objAlarmToByteBuf(o, 1, 0); //历史包结构
                        li.Add((byte)t.Count);
                        li.Add((byte)(t.Count >> 8));
                        li.AddRange(t);
                    }
                }
                li.AddRange(hh);
                //存入文件
                string FilePath = System.Environment.CurrentDirectory;
                string filename =FilePath +"\\"+ c_Config.sysConfig.TelexCode+"-" + stime.ToString() + "-" + etime.ToString()+".tdf";
                FileStream fs = new FileStream(filename, FileMode.Create);
                fs.Write(li.ToArray(), 0, li.Count);
                fs.Close();

                //ReadReplayFile(filename);

                HasRepaly(filename, new EventArgs());
            }
            else
            {
                MessageBox.Show("回放数据获取错误");
            }
        }

        static bool ReplayDataIsRight(List<byte>li,int m)
        {
            string jystr = "";
            byte[] jybuf = new byte[12];
            Array.Copy(li.ToArray(), m, jybuf, 0, 12);
            jystr = System.Text.Encoding.Default.GetString(jybuf);
            if (jystr != "铁大电信回放") return false;
            else return true;
        }
        /// <summary>
        /// 读取回放文件，回放进场启动后读取
        /// </summary>
        /// <param name="FileName"></param>
        static public void ReadReplayFile(string FileName)
        {
            DateTime dt = DateTime.Now;
            AnalogReplayValueList.Clear();
            HighAnalogReplayValueList.Clear();
            KGL_ReplayValueList.Clear();
            AlarmReplayValueList.Clear();
            FileStream fs = new FileStream(FileName, FileMode.Open,FileAccess.Read);
            
            //List<byte> li = new List<byte>();
            byte[] li = new byte[fs.Length];
            fs.Read(li,0,(int)fs.Length);
            fs.Close();
            int m = 0;
            if (ReplayDataIsRight(li.ToList(), m) == false)
            {
                MessageBox.Show("回放数据损坏");
                return;
            }
            m += 12;
            int atnum = li[m++];    //模拟量类型数目
            for (int i = 0; i < atnum; i++)
            {
                int t = li[m]+(li[m+1]<<8);                   //模拟量类型
                m += 2;
                int tlen = li[m] + (li[m + 1] << 8);  //模拟量类型个数
                m += 2;
                List<ReplayClass> rcList = new List<ReplayClass>();
                for (int j = 0; j < tlen; j++)
                {
                    ReplayClass orc = new ReplayClass();
                    orc.AnalogNo = li[m] + (li[m + 1] << 8);    //模拟量序号
                    m += 2;
                    orc.objSet = c_Device.GetSingleAnalogConfig_Inf((AnalogCodeType)t, orc.AnalogNo);
                    int vsum = li[m] + (li[m + 1] << 8);        //该路模拟量的值的个数
                    m+=2;
                    for (int x = 0; x < vsum; x++)
                    {
                        objTimeValue otv = new objTimeValue();
                        otv.u_time = li[m] + (li[m + 1] << 8) + (li[m + 2] << 16) + (li[m + 3] << 24);
                        m += 4;
                        otv.Dvalue = (short)(li[m] + (li[m + 1] << 8));
                        m += 2;
                        string typeName = c_Device.GetAnalogTypeName((AnalogCodeType)t);
                        otv.Tvalue = c_RealTimeValue.ConvertAnalogValue(typeName, otv.Dvalue);
                        orc.ValueList.Add(otv);
                    }
                    rcList.Add(orc);
                }
                if (AnalogReplayValueList.ContainsKey((AnalogCodeType)t))
                {
                    MessageBox.Show("回放数据损坏，键值错误");
                    return;
                }
                else AnalogReplayValueList.Add((AnalogCodeType)t, rcList);
            }
            if (ReplayDataIsRight(li.ToList(), m) == false)
            {
                MessageBox.Show("回放数据损坏");
                return;
            }
            m += 12;
            //以下解高频模拟量
            int gatnum = li[m++];
            for (int i = 0; i < gatnum; i++)
            {
                int t = li[m] + (li[m + 1] << 8);                   //模拟量类型
                m += 2;
                int tlen = li[m] + (li[m + 1] << 8);  //模拟量类型个数
                m += 2;
                List<HighReplayClass> hrclist = new List<HighReplayClass>();
                for (int j = 0; j < tlen; j++)
                {
                    HighReplayClass hrc = new HighReplayClass();
                    hrc.AnalogNo = li[m] + (li[m + 1] << 8);    //模拟量序号
                    m += 2;
                    hrc.objSet = c_Device.GetSingleAnalogConfig_Inf((AnalogCodeType)t, hrc.AnalogNo);
                    int vsum = li[m] + (li[m + 1] << 8);        //该路模拟量的值的个数
                    m+=2;
                    for (int x = 0; x < vsum; x++)
                    {
                        HigFreAnalogValue hav = new HigFreAnalogValue();
                        hav.utime = li[m] + (li[m + 1] << 8) + (li[m + 2] << 16) + (li[m + 3] << 24);
                        m += 4;
                        int vlen = li[m] + (li[m + 1] << 8);
                        m += 2;
                        for (int y = 0; y < vlen; y++)
                        {
                            objHigFre ohf = new objHigFre();
                            ohf.wValue = (short)(li[m] + (li[m + 1] << 8));
                            m += 2;
                            string typeName = c_Device.GetAnalogTypeName((AnalogCodeType)t);
                            ohf.fValue = c_RealTimeValue.ConvertAnalogValue(typeName, ohf.wValue);
                            hav.SecondValueList.Add(ohf);
                        }
                        hrc.ValueList.Add(hav);
                    }
                    hrclist.Add(hrc);
                }
                if (HighAnalogReplayValueList.ContainsKey((AnalogCodeType)t))
                {
                    MessageBox.Show("回放数据损坏，键值错误");
                    return;
                }
                else HighAnalogReplayValueList.Add((AnalogCodeType)t, hrclist);
            }
            if (ReplayDataIsRight(li.ToList(), m) == false)
            {
                MessageBox.Show("回放数据损坏");
                return;
            }
            m += 12;
            //以下解开关量
            int knum = li[m] + (li[m + 1] << 8);  //开关量条数
            m += 2;
            for (int i = 0; i < knum; i++)
            {
                ObjKGL ok = new ObjKGL();
                ok.u_time = li[m] + (li[m + 1] << 8) + (li[m + 2] << 16) + (li[m + 3] << 24);
                m += 4;
                ok.type = li[m++];
                ok.len = (short)(li[m] + (li[m + 1] << 8));
                m += 2;
                Array.Copy(li.ToArray(), m, ok.v, 0, ok.len);
                m += ok.len;
                KGL_ReplayValueList.Add(ok);
            }
            if (ReplayDataIsRight(li.ToList(), m) == false)
            {
                MessageBox.Show("回放数据损坏");
                return;
            }
            m += 12;
            ///报警
            int bjnum = li[m] + (li[m + 1] << 8);   //报警类型数目
            m+=2;
            for (int i = 0; i < bjnum; i++)
            {
                byte t = li[m++];   //报警类型码
                int tnum = li[m] + (li[m + 1] << 8);    //该报警类型报警条数
                m += 2;
                List<ObjAlaram> objlist = new List<ObjAlaram>();
                for (int j = 0; j < tnum; j++)
                {
                    int size = li[m] + (li[m + 1] << 8);  //一条报警的字节数.
                    m+=2;
                    byte[] sbuf = new byte[size + 2];
                    sbuf[0] = 1;
                    sbuf[1] = 0;
                    Array.Copy(li.ToArray(), m, sbuf, 2, size);
                    m += size;
                    List<ObjAlaram> obj = byteBufToObjAlarmList(sbuf, 0, 1, 0);
                    ObjAlaram o = obj[0];
                    objlist.Add(o);
                }
                if (AlarmReplayValueList.ContainsKey(t))
                {
                    MessageBox.Show("回放数据损坏");
                    return;
                }
                else AlarmReplayValueList.Add(t, objlist);
            }
            if (ReplayDataIsRight(li.ToList(), m) == false)
            {
                MessageBox.Show("回放数据损坏");
                return;
            }
            string dl = DateTime.Now.Subtract(dt).TotalSeconds.ToString();
            Console.WriteLine(string.Format("回放数据读取成功,耗时：{0}s",dl));

            MessageBox.Show(string.Format("回放数据读取成功,耗时：{0}s", dl));

        }
        /// <summary>
        /// 获取单个高频模拟量一秒内的状态，回放时用.
        /// </summary>
        /// <param name="utime"></param>
        /// <param name="type"></param>
        /// <param name="devNo"></param>
        /// <returns></returns>
        private static HigFreAnalogValue GetHighSingleDevNoValue(int utime,AnalogCodeType type,int devNo)
        {
            HigFreAnalogValue rtn = new HigFreAnalogValue();
            rtn.utime = utime;
            rtn.SecondValueList.Clear();
            if(type == AnalogCodeType.半自动闭塞电压和电流)
            {
                if (HighAnalogReplayValueList.ContainsKey(type))
                {
                    for (int i = 0; i < HighAnalogReplayValueList[type].Count; i++)
                    {
                        HighReplayClass obj = HighAnalogReplayValueList[type][i];
                        if (obj.AnalogNo == devNo)   //找到了设备
                        {
                            foreach (HigFreAnalogValue v in obj.ValueList)
                            {
                                if (v.utime > utime) break;
                                if (v.utime == utime)
                                {
                                    rtn.utime = utime;
                                    rtn.SecondValueList = v.SecondValueList;
                                    return rtn;
                                }
                            }
                            return rtn;  //找到了当前设备，但没有找到值
                        }
                    }
                }
            }
            return rtn;
        }
        /// <summary>
        /// 获取单个模拟量数据，回放时，实时表格用
        /// </summary>
        /// <param name="utime"></param>
        /// <param name="type"></param>
        /// <param name="devNo"></param>
        /// <returns></returns>
        private static ObjValue GetSingleDevNoValue(int utime,AnalogCodeType type,int devNo)
        {
            ObjValue rtn = new ObjValue();
            rtn.DecimalNum = 0;
            rtn.Value = -1;
            rtn.ValueType = c_Device.GetAnalogTypeName(type);
            if (devNo == -1) return rtn;
            if(type == AnalogCodeType.半自动闭塞电压和电流)
            {
             
            }
            else
            {
                if(AnalogReplayValueList.ContainsKey(type))
                {
                    for(int i = 0;i<AnalogReplayValueList[type].Count;i++)
                    {
                        ReplayClass obj = AnalogReplayValueList[type][i];
                        if(obj.AnalogNo == devNo)   //找到了设备
                        {
                            int tmptime = utime;
                            int xhcount = 10;
                            while(xhcount>0)
                            {
                                xhcount--;
                                foreach(objTimeValue v in obj.ValueList)
                                {
                                    if (v.u_time > tmptime) break;
                                    if(v.u_time == tmptime)
                                    {
                                        rtn = v.Tvalue;
                                        return rtn;
                                    }
                                }
                                tmptime--;  //当前秒没有数据，当前秒减1后再去查找.找前一个值，前10秒没有数据，认为是终端，返回-1.
                            }
                            return rtn;  //找到了当前设备，但没有找到值
                        }
                    }
                }
            }
            return rtn;
        }
        /// <summary>
        /// 获取单个开关量状态，内部用于回放时实时表格展示
        /// </summary>
        /// <param name="utime"></param>
        /// <param name="devNo"></param>
        /// <returns></returns>
        private static ObjValue GetSingleKGLvalue(int utime,int devNo)
        {
            ObjValue rtn = new ObjValue();
            rtn.ValueType = "开关量";
            rtn.DecimalNum = 0;
            for (int i = 0; i < KGL_ReplayValueList.Count; i++)
            {
                ObjKGL obj = KGL_ReplayValueList[i];
                if (obj.type == 1)    //全体开关量
                {
                    if (obj.u_time <= utime) //取最接近的一包全体开关量的值
                    {
                        int x = devNo / 8;
                        if (devNo % 8 != 0) x++;
                        int y = (devNo % 8);
                        if (x < obj.len) rtn.Value = ((obj.v[x] >> y) & 0x01);
                    }
                    else return rtn;
                }
                else if (obj.type == 0) //变化开关量
                {
                    for (int j = 0; j < obj.len; j++)
                    {
                        int ttime = obj.v[j] + (obj.v[j + 1] << 8) + (obj.v[j + 2] << 16) + (obj.v[j + 3] << 24);
                        j += 4;
                        int no = obj.v[j] + (obj.v[j + 1] << 8);
                        j += 2;
                        byte s = (byte)(no >> 15);
                        no = no & 0x7ffff;
                        if (ttime <= utime)  //取最接近的一包变化开关量的值。
                        {
                            if (no == devNo) rtn.Value = s;
                        }
                        else return rtn;
                    }
                }
            }
            return rtn;
        }
        /// <summary>
        /// 外部调用，获取某一种类型的模拟量的值，用于回放表格展示
        /// </summary>
        /// <param name="utime"></param>
        /// <param name="CSMType"></param>
        /// <returns></returns>
        public static List<ObjRealTimeValue> GetReplayCsmList(int utime, string CSMType)
        {
            List<ObjRealTimeValue> rli = new List<ObjRealTimeValue>();
            if(c_Device.DeviceMsgGather.ContainsKey(CSMType))
            {
                objMsgGatherStruct obj = c_Device.DeviceMsgGather[CSMType];
                for(int i = 0;i<obj.DevList.Count;i++)
                {
                    ObjRealTimeValue d = new ObjRealTimeValue();
                    d.DevName = obj.DevList[i].DevName;
                    for(int j = 0;j<obj.ArrtiList.Count;j++)
                    {
                        AnalogCodeType type = obj.ArrtiList[j].AnalogType;
                        int devno = obj.DevList[i].AnalogSet[j];
                        ObjValue v = new ObjValue();
                        if(type == AnalogCodeType.None)
                        {
                            v = GetSingleKGLvalue(utime, devno);
                        }
                        else
                        {
                            v = GetSingleDevNoValue(utime, type, devno);
                        }
                        d.DevValue.Add(v);
                    }
                    rli.Add(d);
                }
            }
            return rli;
        }
        /// <summary>
        /// 外部查找单个模拟量的值，用于回放曲线。
        /// </summary>
        /// <param name="utime"></param>
        /// <param name="CsmType"></param>
        /// <param name="DevName"></param>
        /// <param name="AttriName"></param>
        /// <returns></returns>
        public static ObjValue GetReplaySingleAnalogValue(int utime, string CsmType, string DevName, string AttriName)
        {
            ObjValue rtn = new ObjValue();
            rtn.DecimalNum = 0;
            rtn.Value = -1;
            rtn.ValueType = "";
            if (c_Device.DeviceMsgGather.ContainsKey(CsmType))
            {
                objMsgGatherStruct obj = c_Device.DeviceMsgGather[CsmType];
                for(int i = 0;i<obj.ArrtiList.Count;i++)
                {
                    if (obj.ArrtiList[i].AttriName == AttriName)
                    {
                        for(int j = 0;j<obj.DevList.Count;j++)
                        {
                            if(obj.DevList[j].DevName== DevName)
                            {
                                int devno = obj.DevList[j].AnalogSet[i];
                                AnalogCodeType type = obj.ArrtiList[i].AnalogType;
                                if(type == AnalogCodeType.None)
                                {
                                    rtn = GetSingleKGLvalue(utime,devno);
                                }
                                else if(type == AnalogCodeType.半自动闭塞电压和电流){}
                                else
                                {
                                    rtn = GetSingleDevNoValue(utime, type, devno);
                                }
                                return rtn;
                            }
                        }
                    }
                }
            }
            return rtn;
        }
        /// <summary>
        /// 取单个开关量一秒内的变化值，用于回放时的开关量表格显示. 一秒内可能变化多次
        /// </summary>
        /// <param name="utime"></param>
        /// <param name="devNo"></param>
        /// <returns></returns>
        public static string GetReplayKGLValue(int utime, int devNo)
        {
            string rets = "";
            string mids = "";
            for (int i = 0; i < KGL_ReplayValueList.Count; i++)
            {
                ObjKGL obj = KGL_ReplayValueList[i];
                if (obj.type == 1)    //全体开关量
                {
                    if (obj.u_time < utime) //取最接近的一包全体开关量的值
                    {
                        int x = devNo / 8;
                        if (devNo % 8 != 0) x++;
                        int y = (devNo % 8);
                        if (x < obj.len)
                        {
                            int tt = ((obj.v[x] >> y) & 0x01);
                            if (tt == 1) mids = "↑";
                            else mids = "↓";
                        }
                    }
                    else if (obj.u_time == utime)
                    {
                        int x = devNo / 8;
                        if (devNo % 8 != 0) x++;
                        int y = (devNo % 8);
                        if (x < obj.len)
                        {
                            int tt = ((obj.v[x] >> y) & 0x01);
                            if (tt == 1) mids = " ↑ ";
                            else mids = " ↓ ";
                            rets = rets +  mids;
                        }
                    }
                    else
                    {
                        if (rets == "") //只有没找到全部时间相等的全体，才取上一包全体
                        {
                            rets = mids;
                        }
                        return rets;
                    }
                }
                else if (obj.type == 0) //变化开关量
                {
                    for (int j = 0; j < obj.len; j++)
                    {
                        int ttime = obj.v[j] + (obj.v[j + 1] << 8) + (obj.v[j + 2] << 16) + (obj.v[j + 3] << 24);
                        j += 4;
                        int no = obj.v[j] + (obj.v[j + 1] << 8);
                        j += 2;
                        byte s = (byte)(no >> 15);
                        no = no & 0x7fff;
                        if (ttime == utime)  //取最接近的一包变化开关量的值。
                        {
                            if (no == devNo)
                            {
                                if (s == 1) rets = rets + " ↑ ";
                                else rets = rets + " ↓ ";
                            }
                        }
                        if (ttime > utime) return rets;
                    }
                }
            }
            return rets;
        }
        /// <summary>
        /// 获取一秒中的开关量状态，用于站场回放
        /// </summary>
        /// <param name="stime"></param>
        /// <returns></returns>
        public static objRevKGL GetKGL_Data(int stime)
        {
            objRevKGL rtn = new objRevKGL();
            rtn.AllFlag = true;
            rtn.time = stime;
            rtn.kglNum = c_Device.KGL_Config.Count;
            byte b = 0;
            for(int i = 0;i<c_Device.KGL_Config.Count;i++)
            {
                if (i > 1 && (i % 8 == 0)) //整数时入队列
                {
                    rtn.Value.Add(b);
                    b = 0;
                }
                int devno = c_Device.KGL_Config[i].ADNumber;
                ObjValue v = GetSingleKGLvalue(stime, devno);
                byte rv = (byte)(v.Value);
                rv = (byte)(rv & 0x01);
                b |= (byte)(rv << (i % 8));
                
            }
            return rtn;
        }
        /// <summary>
        /// 获取回放状态下,一秒内的报警条数
        /// </summary>
        /// <param name="stime"></param>
        /// <returns></returns>
        static public List<HistroyAlarmObj> GetAlarmData(int stime)
        {
            List<HistroyAlarmObj> li = new List<HistroyAlarmObj>();
            foreach(KeyValuePair<byte,List<ObjAlaram>> k in AlarmReplayValueList)
            {
                HistroyAlarmObj obj = new HistroyAlarmObj();
                for(int i = 0;i<k.Value.Count;i++)
                {
                    if(k.Value[i].u_time == stime)
                    {
                        obj = ConvertAlarmObjToDisplay(k.Value[i]);
                        li.Add(obj);
                    }
                }
            }
            return li;
        }
    }
}
